#include <QStringList>
#include <QDateTime>
#include "dataspecificationutils.h"
#include "dataspecification_def.h"
#include "private/spectrumdatafilecommondefine.h"
#include <QDebug>

namespace DataSpecificationGW
{
    namespace
    {
        const std::map<SpectrumTypeCode, QString> qmapCodeNames =
        {
            { SPECTRUM_CODE_UHF_PRPD, STR_FILE_NODE_PRPD },
            { SPECTRUM_CODE_UHF_PRPS, STR_FILE_NODE_PRPS },
            { SPECTRUM_CODE_HFCT_PRPD, STR_FILE_NODE_PRPD },
            { SPECTRUM_CODE_HFCT_PRPS, STR_FILE_NODE_PRPS },
            { SPECTRUM_CODE_AE_AMP, STR_FILE_NODE_AE_AMP },
            { SPECTRUM_CODE_AE_PULSE, STR_FILE_NODE_AE_PULSE },
            { SPECTRUM_CODE_AE_PHASE, STR_FILE_NODE_AE_PHASE },
            { SPECTRUM_CODE_AE_WAVE, STR_FILE_NODE_AE_WAVE },
            { SPECTRUM_CODE_TEV_AMP, STR_FILE_NODE_TEV_AMP },
            { SPECTRUM_CODE_MECH_MULTI, STR_FILE_NODE_MECHANICAL },
            { SPECTRUM_CODE_MECH_ELEC_I, STR_FILE_NODE_MECHANICAL_COIL },
            { SPECTRUM_CODE_MECH_ELEC_U, STR_FILE_NODE_MECHANICAL },
            { SPECTRUM_CODE_MECH_MOTOR_I, STR_FILE_NODE_MECHANICAL_MOTOR },
            { SPECTRUM_CODE_MECH_MOTOR_U, STR_FILE_NODE_MECHANICAL },
            { SPECTRUM_CODE_MECH_CT_I, STR_FILE_NODE_MECHANICAL },
            { SPECTRUM_CODE_MECH_SWITCH, STR_FILE_NODE_MECHANICAL_SWITCH },
            { SPECTRUM_CODE_MECH_ROUTE, STR_FILE_NODE_MECHANICAL },
            { SPECTRUM_CODE_MECH_VIBRA, STR_FILE_NODE_MECHANICAL },
            { SPECTRUM_CODE_MECH_RESIST, STR_FILE_NODE_MECHANICAL },
            { SPECTRUM_CODE_INFRARED, STR_FILE_NODE_INFRARED },
            { SPECTRUM_CODE_CURRENT_AMPLITUDE, STR_FILE_NODE_CURRENT_AMP },
        };
    }

    DataSpecificationUtils::DataSpecificationUtils()
    {
    }

    DataSpecificationUtils::~DataSpecificationUtils()
    {
    }

    /************************************************
     * 函数名   : saveBinaryPointerData
     * 输入参数 :
       const DataSpecificationGW::StorageDataType eStorageDataType: 数据保存类型
       void* pData: 数据
       const int iDataSize: 数据大小
     * 输出参数 :
       QDataStream& out: 二进制数据流
     * 返回值   : void
     * 功能     : 保存二进制指针数据
     ************************************************/
    void DataSpecificationUtils::saveBinaryPointerData(QDataStream &out, const StorageDataType eStorageDataType, void *pData, const int iDataSize)
    {
        if (Q_NULLPTR != pData)
        {
            switch (eStorageDataType)
            {
            case DATA_TYPE_INT8:
            {
                qint8 * cData = (qint8 *)pData;
                for (int i = 0; i < iDataSize; i++)
                {
                    out << cData[i];
                }
            }
                break;
            case DATA_TYPE_UINT8:
            {
                quint8 * ucData = (quint8 *)pData;
                for (int i = 0; i < iDataSize; i++)
                {
                    out << ucData[i];
                }
            }
                break;
            case DATA_TYPE_INT16:
            {
                qint16 * sData = (qint16 *)pData;
                for (int i = 0; i < iDataSize; i++)
                {
                    out << sData[i];
                }
            }
                break;
            case DATA_TYPE_INT32:
            {
                qint32 * iData = (qint32 *)pData;
                for (int i = 0; i < iDataSize; i++)
                {
                    out << iData[i];
                }
            }
                break;
            case DATA_TYPE_INT64:
            {
                qint64 * llData = (qint64 *)pData;
                for (int i = 0; i < iDataSize; i++)
                {
                    out << llData[i];
                }
            }
                break;
            case DATA_TYPE_FLOAT:
            {
                QDataStream::FloatingPointPrecision flag = out.floatingPointPrecision();
                out.setFloatingPointPrecision(QDataStream::SinglePrecision);
                float * fData = (float *)pData;
                for (int i = 0; i < iDataSize; i++)
                {
                    out << fData[i];
                }
                out.setFloatingPointPrecision(flag);
            }
                break;
            case DATA_TYPE_DOUBLE:
            {
                QDataStream::FloatingPointPrecision flag = out.floatingPointPrecision();
                out.setFloatingPointPrecision(QDataStream::DoublePrecision);
                double * dData = (double *)pData;
                for (int i = 0; i < iDataSize; i++)
                {
                    out << dData[i];
                }
                out.setFloatingPointPrecision(flag);
            }
                break;
            case DATA_TYPE_UINT16:
            {
                quint16 * usData = (quint16 *)pData;
                for (int i = 0; i < iDataSize; i++)
                {
                    out << usData[i];
                }
            }
                break;
            default:
                break;
            }
        }
    }

    /************************************************
     * 函数名   : parseBinaryPointerData
     * 输入参数 :
       QDataStream& in: 二进制数据流
       const DataSpecificationGW::StorageDataType eStorageDataType: 数据保存类型
       const int iDataSize: 数据大小
     * 输出参数 :
       QByteArray& qbaData: 数据
     * 返回值   : void
     * 功能     : 解析二进制指针数据
     ************************************************/
    void DataSpecificationUtils::parseBinaryPointerData(QDataStream &in, const StorageDataType eStorageDataType, QByteArray& qbaData, const int iDataSize)
    {
        int iBufSize = DataSpecificationUtils::calcDataBufferSize(iDataSize, eStorageDataType);
        qbaData.resize(iBufSize);
        in.readRawData(reinterpret_cast<char *>(qbaData.data()), iBufSize);
    }

    /************************************************
     * 函数名   : saveBinaryReservedData
     * 输入参数 :
       const int iLength: 长度
     * 输出参数 :
           QDataStream& out: 二进制数据流
     * 返回值   : void
     * 功能     : 保存二进制预留数据
     ************************************************/
    void DataSpecificationUtils::saveBinaryReservedData(const int iLength, QDataStream& out)
    {
        if (iLength <= 0)
        {
            return;
        }

        for (int i = 0; i < iLength; ++i)
        {
            out << (quint8)gs_ucUnrecordedByteValue;
        }
    }

    /************************************************
     * 函数名   : convertStringToBinary
     * 输入参数 :
       const QString& qstrData: 字符串数据
       const StringType eStringType: 字符串类型
       const quint16 usDataLength: 数据长度
     * 输出参数 :
       QDataStream& out: 二进制数据流
     * 返回值   : void
     * 功能     : 将字符串转换成二进制
     ************************************************/
    void DataSpecificationUtils::convertStringToBinary(const QString& qstrData, const StringType eStringType, QDataStream& out, const quint16 usDataLength)
    {
        switch (eStringType)
        {
        case TYPE_VERSION:
        {
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
            QStringList qstrList = qstrData.split(".", QString::SkipEmptyParts);
#else
#include <Qt> // Qt 6 需要包含 Qt 命名空间
            QStringList qstrList = qstrData.split(".", Qt::SkipEmptyParts);
#endif
            if (usDataLength == qstrList.size())
            {
                for (int i = 0; i < usDataLength; ++i)
                {
                    out << (quint8)qstrList[i].toUInt();
                }
            }
            else
            {
                for (int i = 0; i < usDataLength; ++i)
                {
                    out << (quint8)0;
                }
            }
        }
        break;
        case TYPE_UNICODE:
        {
            const ushort* pData = qstrData.utf16();
            int i = 0;
            while ((pData[i] != 0) && (i < (usDataLength / 2 - 1)))
            {
                out << (quint16)pData[i];
                i++;
            }
            for (; i < usDataLength / 2; ++i)
            {
                out << (quint16)0;
            }
        }
        break;
        case TYPE_ASCII:
        {
            char caData[usDataLength];
            memset(caData, 0, usDataLength);
            qint16 sDataLength = qstrData.toLatin1().size();//strData.toAscii().size();
            if (sDataLength <= usDataLength)
            {
                memcpy(caData, qstrData.toLatin1(), sDataLength);
            }
            else
            {
                memcpy(caData, qstrData.toLatin1(), usDataLength);
            }
            for (int i = 0; i < usDataLength; i++)
            {
                out << (qint8)caData[i];
            }
        }
        break;
        case TYPE_DATETIME:
        {
            out << serializeDateTime(qstrData);
        }
            break;
        default:
            break;
        }
    }

    /************************************************
     * 函数名   : serializeDateTime
     * 输入参数 :
       const QString& qstrDateTime: 日期字符串
     * 输出参数 : NULL
     * 返回值   : qint64
     * 功能     : 序列化日期
     ************************************************/
    qint64 DataSpecificationUtils::serializeDateTime(const QString& qstrDateTime)
    {
        QString qstrDateTimeTmp = qstrDateTime;
        QDateTime dataTime = QDateTime::fromString(qstrDateTime, "yyyyMMddHHmmsszzz");
        if (!dataTime.isValid())
        {
            dataTime = QDateTime::currentDateTime();
            qstrDateTimeTmp = dataTime.toString("yyyyMMddHHmmsszzz");
        }

        return qstrDateTimeTmp.toLongLong();
    }

    /************************************************
     * 函数名   : calcDataBufferSize
     * 输入参数 :
       const quint32 iBufferCount: 数据个数
       const DataSpecificationGW::StorageDataType eStorageDataType: 数据保存类型
     * 输出参数 : NULL
     * 返回值   : int
     * 功能     : 计算数据缓存的占用空间大小
     ************************************************/
    int DataSpecificationUtils::calcDataBufferSize(const quint32 iBufferCount, const DataSpecificationGW::StorageDataType eStorageDataType)
    {
        switch (eStorageDataType)
        {
        case DataSpecificationGW::DATA_TYPE_FLOAT:
        {
            return iBufferCount * sizeof(float);
        }
        case DataSpecificationGW::DATA_TYPE_DOUBLE:
        {
            return iBufferCount * sizeof(double);
        }
        case DataSpecificationGW::DATA_TYPE_INT16:
        {
            return iBufferCount * sizeof(qint16);
        }
        case DataSpecificationGW::DATA_TYPE_UINT16:
        {
            return iBufferCount * sizeof(quint16);
        }
        case DataSpecificationGW::DATA_TYPE_UINT8:
        {
            return iBufferCount * sizeof(quint8);
        }
        case DataSpecificationGW::DATA_TYPE_INT8:
        {
            return iBufferCount * sizeof(qint8);
        }
        case DataSpecificationGW::DATA_TYPE_INT32:
        {
            return iBufferCount * sizeof(qint32);
        }
        case DataSpecificationGW::DATA_TYPE_INT64:
        {
            return iBufferCount * sizeof(qint64);
        }
        default:
            break;
        }

        return 0;
    }

    /************************************************
     * 函数名   : getUnicode
     * 输入参数 :
       QDataStream& in: 输入流
       const size_t: 大小
     * 输出参数 :
       qstrDest: 输出字符串
     * 返回值   : bool
     * 功能     : 读取Unicode字符串
     ************************************************/
    bool DataSpecificationUtils::getUnicode(QDataStream& in, const size_t size, QString& qstrDest)
    {
        qstrDest.clear();

        QChar c; // 16个字节，所以size要除以2
        for (size_t i = 0; i < size / 2; ++i)
        {
            in >> c;
            if (c != '\0')
            {
                qstrDest.append(c);
            }
        }

        return (in.status() == QDataStream::Ok);
    }

    /************************************************
     * 函数名   : getAscii
     * 输入参数 :
       QDataStream& in: 输入流
       const size_t: 大小
     * 输出参数 :
       qstrDest: 输出字符串
     * 返回值   : bool
     * 功能     : 读取Ascii字符串
     ************************************************/
    bool DataSpecificationUtils::getAscii(QDataStream& in, const size_t size, QString& qstrDest)
    {
        qstrDest.clear();

        qint8 c;
        for (size_t i = 0; i < size; ++i)
        {
            in >> c;
            if (c != '\0')
            {
                qstrDest.append(QChar(c));
            }
        }

        return (in.status() == QDataStream::Ok);
    }

    /************************************************
     * 函数名   : getUint8Vector
     * 输入参数 :
       QDataStream& in: 输入流
       const size_t: 大小
     * 输出参数 :
       vecValue: 输出vector
     * 返回值   : bool
     * 功能     : 读取uint8类型的vector
     ************************************************/
    bool DataSpecificationUtils::getUint8Vector(QDataStream& in, const size_t size, std::vector<quint8>& vecValue)
    {
        vecValue.reserve(size);
        for (size_t i = 0; i < size; ++i)
        {
            quint8 tmpValue;
            in >> tmpValue;
            vecValue.push_back(tmpValue);
        }

        return (in.status() == QDataStream::Ok);
    }

    /************************************************
     * 函数名   : dischargeTypeProbabilityVector2QString
     * 输入参数 :
       const std::vector<quint8>& vecPDTypePR: 放电类型概率vector
     * 输出参数 : NULL
     * 返回值   : QString
     * 功能     : 放电类型概率vector类型转QString
     ************************************************/
    QString DataSpecificationUtils::dischargeTypeProbabilityVector2QString(const std::vector<quint8>& vecPDTypePR)
    {
        QString qstrPR;
        //放电概率
        for (int i = 0; i < 8; ++i)
        {
            if (i >= vecPDTypePR.size())
            {
                break;
            }
            QString strPRTemp = QString::number(vecPDTypePR[i]);
            qstrPR = qstrPR + strPRTemp;
            qstrPR = qstrPR + ",";
        }
        qstrPR.remove(qstrPR.size() - 1, 1);

        return qstrPR;
    }

    void* DataSpecificationUtils::createDataBuffer(const quint32 iBufCnt, const StorageDataType eStorageDataType, unsigned long& iBufSize)
    {
        void *pData = NULL;

        if( iBufCnt > 0 )
        {
            switch( eStorageDataType )
            {
            case DATA_TYPE_FLOAT:
            {
                float *pfData = new float[iBufCnt];
                pData = (void*)pfData;
                iBufSize = sizeof(float) *iBufCnt;
            }
                break;
            case DATA_TYPE_DOUBLE:
            {
                double *pdData = new double[iBufCnt];
                pData = (void*)pdData;
                iBufSize = sizeof(double) *iBufCnt;
            }
                break;

            case DATA_TYPE_INT16:
            {
                short *psData = new short[iBufCnt];
                pData = (void *)psData;
                iBufSize = sizeof(short) * iBufCnt;
            }
                break;
            case DATA_TYPE_UINT16:
            {
                unsigned short *psData = new unsigned short[iBufCnt];
                pData = (void *)psData;
                iBufSize = sizeof(unsigned short) * iBufCnt;
            }
                break;
            case DATA_TYPE_UINT8:
            {
                quint8 *psData = new quint8[iBufCnt];
                pData = (void *)psData;
                iBufSize = sizeof(quint8) * iBufCnt;
            }
                break;
            case DATA_TYPE_INT8:
            {
                qint8 *psData = new qint8[iBufCnt];
                pData = (void *)psData;
                iBufSize = sizeof(qint8) * iBufCnt;
            }
                break;
            case DATA_TYPE_INT32:
            {
                qint32 *psData = new qint32[iBufCnt];
                pData = (void *)psData;
                iBufSize = sizeof(qint32) * iBufCnt;
            }
                break;
            case DATA_TYPE_INT64:
            {
                qint64 *psData = new qint64[iBufCnt];
                pData = (void *)psData;
                iBufSize = sizeof(qint64) * iBufCnt;
            }
                break;
            case DATA_TYPE_UNUSED:
            {
                qWarning()<<"DataSpecificationUtils::createDataBuf: data type is unused! ";
            }
                break;
            }
        }

        return pData;
    }

    bool DataSpecificationUtils::deleteDataBuffer(void** pBuf, const StorageDataType eStorageDataType)
    {
        Q_UNUSED(eStorageDataType);
        bool bSuccess = true;
        if( ( NULL != pBuf) && ( NULL != *pBuf ) )
        {
            delete [] *pBuf;
            *pBuf = NULL;
        }
        else
        {
            bSuccess = false;
        }
        return bSuccess;
    }

    /************************************************
     * 函数名   : spectrumTypeCodeEnum2QString
     * 输入参数 :
       const SpectrumCode eSpectrumCode: 图谱类型编码
     * 输出参数 : NULL
     * 返回值   : QString
     * 功能     : 图谱类型编码枚举转QString
     ************************************************/
    QString DataSpecificationUtils::spectrumTypeCodeEnum2QString(const SpectrumTypeCode eSpectrumCode)
    {
        if (qmapCodeNames.find(eSpectrumCode) != qmapCodeNames.end())
        {
            return qmapCodeNames.at(eSpectrumCode);
        }

        return "";
    }

}
